import WKSDK, {
  ConnectStatus,
  Message,
  MessageText,
  Channel,
  /*  ChannelTypePerson, */
  ChannelTypeGroup,
  MessageImage,
  SendackPacket,
  SyncOptions,
} from "wukongimjssdk";
import { MsgVoiceContent } from "./components/msg-type/bean/msg-voice";
import { MsgVideoContent } from "./components/msg-type/bean/msg-video";
import {
  getImAuthToken,
  getImRoute,
  getServicePersonList,
  initiateConversation,
  channelDetailByParams,
  getKfConversationSetting,
} from "./api";
import store from "./utils/store";
import configProvider from "./utils/config-provider/index";
import { registerMsgType } from "./components/msg-type/bean";
import { WechatInfoContent } from "./components/msg-type/bean/wecat-info";
import listenLineUp from "./utils/service/line-up";
import type { SelectServiceParams, InitChannelData, LoginInfo, OnMessageAsyncCallback } from "./types/index";

// 看到此报错，是因为没有配置vue.config.js的【transpileDependencies】，详见：https://www.uviewui.com/components/npmSetting.html#_5-cli模式额外配置
const pleaseSetTranspileDependencies = {},
  babelTest = pleaseSetTranspileDependencies?.test;

/**
 * Kingon Custom Service IM
 */
export default class KOCSIM {
  // 当前实例
  private static instance: KOCSIM;
  // 初始化状态
  initStatus: boolean = false;
  // 当前通道对象
  currentChannel: Channel = new Channel("0", ChannelTypeGroup);
  // 服务器返回的通道信息
  channelInfo: AnyObject = {};
  // 客服会话设置
  kfConversationSetting = {
    // 是否开启自主选择坐席 0-关闭 1-开启
    isChoose: 0,
    // 是否开启排队转留言设置 0-关闭 1-开启
    isLineConvertLeaveMessage: false,
  };
  // 当前客服
  currentService: AnyObject = {};

  onMessageAsync: OnMessageAsyncCallback = async (message: Message) => {};
  // 连接状态监听
  // connectStatus: (status: ConnectStatus, reasonCode?: number) => void = (
  //   status: ConnectStatus,
  //   reasonCode?: number
  // ) => {
  //   if (status === ConnectStatus.Connected) {
  //     console.log("连接成功", { status, reasonCode });
  //   } else {
  //     // 断开连接
  //     console.log("断开连接", { status, reasonCode });
  //   }
  // };

  constructor() {
    if (KOCSIM.instance) {
      throw new Error("实例已被创建，直接使用 getInstance() 获取实例");
    }
  }

  // 静态方法返回唯一实例
  static inst() {
    if (!KOCSIM.instance) {
      KOCSIM.instance = new KOCSIM();
    }
    return KOCSIM.instance;
  }

  /*  初始化 */
  async init(config: any = {}) {
    console.log("ini KOCSIM ", config);

    if (config.addr) {
      // 单机模式可以直接设置地址
      config.addr = process.env.IM_WS_URL;
    } else {
      // 获取长连接地址
      const { wsAddr, wssAddr /* , tcpAddr */ } = await KOCSIM.inst().getLongConnAddr();

      // 判断当前是否 https
      // #ifdef H5
      if (window.location.protocol === "https:") {
        WKSDK.shared().config.addr = `wss://${wssAddr}`; // 长连接地址
      } else {
        WKSDK.shared().config.addr = `ws://${wsAddr}`; // 长连接地址
      }
      // #endif
      // #ifndef H5
      const preUrl = import.meta.env.VITE_BASE_API.startsWith("https") ? "wss://" : "ws://";
      WKSDK.shared().config.addr = `${preUrl}${wsAddr}`; // 长连接地址
      // #endif
    }
    // 注册自定义配置
    configProvider.init(WKSDK);
    // 注册消息类型
    registerMsgType();

    console.log(
      `
			 ------------------------
			| 🛸 WKSDK config
			 ------------------------ `,
      WKSDK.shared().config
    );

    // 连接状态监听 （WKSDK 的 添加监听并不是唯一，所以必须在用不到的时候删掉）
    // WKSDK.shared().connectManager.addConnectStatusListener(KOCSIM.inst().connectStatus);

    // 初始化本地数据
    store.init();

    // 将当前实例保存到全局
    // @ts-ignore
    uni.$KOCSIM = KOCSIM.inst();

    KOCSIM.inst().initStatus = true;

    // 返回sdk实例
    return WKSDK.shared();
  }

  /**
   * 登录用户
   *  如果本地有用户，则直接使用本地用户
   *  如果传入 上游系统的用户id, 则会返回指定uid
   * PS: 建议：如果业务系统退出登录时，大可不必 调 .logout ，但是登录用户时需要 合适时机调用 .login
   * @param info
   */
  async login(info: LoginInfo = { authToken: "", uid: "" }) {
    // 获取当前用户
    const currentUser = store.getCurrentUser();
    // 判断当前有本地用户，且本地用户所属地址与当前地址一致
    if (currentUser && currentUser.belongAddr == WKSDK.shared().config.addr && !info?.uid) {
      info.uid = currentUser.uid;
      info.authToken = currentUser.authToken;
      WKSDK.shared().config.uid = currentUser.uid; // 用户uid（需要在悟空通讯端注册过）
      WKSDK.shared().config.token = currentUser.authToken; // 用户token （需要在悟空通讯端注册过）
    } else {
      const { uid, authToken, isVisitor } = await KOCSIM.inst().auth(info.uid);
      WKSDK.shared().config.uid = uid; // 用户uid（需要在悟空通讯端注册过）
      WKSDK.shared().config.token = authToken; // 用户token （需要在悟空通讯端注册过）
      store.saveCurrentUser({ uid, authToken, isVisitor, belongAddr: WKSDK.shared().config.addr });
    }
    WKSDK.shared().connectManager.connect();
    console.log("登录成功 :uid", store.getCurrentUser().uid);
  }

  // 退出用户
  async logout() {
    // 断开连接
    WKSDK.shared().connectManager.disconnect();
    // 结束会话
    this.endChannel();
  }

  // 授权
  async auth(uid?: string, type: number = 1) {
    try {
      const pam = {
        type: type,
        customerId: uid,
      };
      const { data } = await getImAuthToken(pam);
      return data;
    } catch (error) {
      console.error("auth error", error);
      throw error;
    }
  }

  // 获取长连接地址
  async getLongConnAddr() {
    const pam = {
      uid: WKSDK.shared().config.uid,
    };
    const { data } = await getImRoute(pam);
    return data;
  }

  // 获取在线的客服列表
  async getOnlineServiceList(params: any = {}) {
    const { data } = await getServicePersonList(params);
    return data;
  }

  // 获取客服会话设置
  async syncKfConvSetting(params: any = {}) {
    const { data } = await getKfConversationSetting(params);
    if (data) {
      Object.assign(KOCSIM.inst().kfConversationSetting, data);
    }
    return data;
  }

  async selectService(params: SelectServiceParams) {
    params.uid = WKSDK.shared().config.uid;
    // 查询是否已存在相同服务人员 servicePersonUserId 的客服通道
    const serviceChannel = store.getServiceChannelByUserId(params.servicePersonUserId);
    const { belongAddr, belongUid } = serviceChannel ?? { belongAddr: null, belongUid: null };
    if (serviceChannel && belongAddr == WKSDK.shared().config.addr && belongUid == WKSDK.shared().config.uid) {
      try {
        // 查询通道状态
        const { data: channelDetail } = await channelDetailByParams({
          channelId: serviceChannel.channelId,
          uid: serviceChannel.customerId,
        });
        if (channelDetail?.channelStatus === "waiting" || channelDetail?.channelStatus === "inConversation") {
          // 通道状态为等待中或会话中, 复用通道
          KOCSIM.inst().setCurrentChannel(serviceChannel);
          console.warn(" ✔ 复用通道", serviceChannel);
          // 返回数据
          return serviceChannel;
        } else {
          // 通道状态为结束 , 重新创建通道
          const { data } = await initiateConversation(params);
          // 设置 当前通道
          KOCSIM.inst().setCurrentChannel(data);
          console.warn(" ✔ 重建通道", data);
          // 返回数据
          return data;
        }
      } catch (error) {
        console.error("查询/重建通道失败", error);
      }
    } else {
      const { data } = await initiateConversation(params);
      // 设置 当前通道
      KOCSIM.inst().setCurrentChannel(data);
      // 返回数据
      return data;
    }
  }

  async handleServiceSelect(service: any) {
    // console.log("handleServiceSelect service", service);

    uni.$emit("KN-IM:serviceListStatusChange", {
      type: "connecting",
      data: service,
    });

    const selectRes = await KOCSIM.inst()
      .selectService({
        servicePersonUserId: service.userId,
        executeType: "create",
      })
      .then((servicerInfo) => {
        // 设置当前选择的客服
        KOCSIM.inst().currentService = servicerInfo;
				return servicerInfo;
      })
      .catch((error) => {
        // 发送客服选择状态
        uni.$emit("KN-IM:serviceListStatusChange", { type: "init" });
        // 抛出错误
        throw error;
      });

    if (selectRes?.channelStatus === "waiting") {
      // 查询客服排队状态
      listenLineUp.init();
    }

    // 发送客服选择状态
    uni.$emit("KN-IM:serviceListStatusChange", {
      type: "selected",
      data: service,
    });

    // 发送连接状态
    uni.$emit("KN-IM:connect-status", "connected");

    // 获取通道历史消息
    await KOCSIM.inst().getChannelMessages({
      startMessageSeq: 0,
      endMessageSeq: 0,
      limit: 20,
      pullMode: 0,
    });
  }

  // 发送消息
  async sendMessage(content: any) {
    // 发送消息之前，先判断当前是否有通道
    console.log("sendMessage -> currentChannel", KOCSIM.inst().currentChannel);
    // === 0 表示没有通道，需要创建通道
    if (KOCSIM.inst().currentChannel?.channelID === "0") {
      // 获取在线客服列表
      await KOCSIM.inst()
        .getOnlineServiceList({ onlineStatus: 1 })
        .then(async (res) => {
          if (res.length > 0) {
            // 如果开启了自主选择坐席，则获取客服会话设置
            // if (wkImUtils.kfConversationSetting.isChoose) {
            //   handleServiceSelect(servicers.value[0]);
            // }

            // 不给客户选择，直接选择一个客服进行会话
            await KOCSIM.inst().handleServiceSelect(res[0]);
          }
        });
    }

    // console.log("sendMessage -> currentChannel",  KOCSIM.inst().currentChannel, content);
    switch (content.type) {
      case 1: {
        const text = new MessageText(content.content);
        WKSDK.shared().chatManager.send(text, KOCSIM.inst().currentChannel);
        break;
      }
      case 2: {
        const image = new MessageImage();
        image.url = content.content; // 自己上传
        image.file = {
          path: content.content,
          name: "image",
        }; // SDK上传
        image.width = 200;
        image.height = 200;
        WKSDK.shared().chatManager.send(image, KOCSIM.inst().currentChannel);
        break;
      }
      case 3: {
        const { url, duration, file } = content.content;
        const voice = new MsgVoiceContent();
        voice.url = url; // 自己上传
        voice.duration = duration;
        voice.file = {
          path: url,
          name: "audio/mp3",
        }; // SDK上传
        console.log("voice", { voice, content });
        WKSDK.shared().chatManager.send(voice, KOCSIM.inst().currentChannel);
        break;
      }
      case 4: {
        const { url, file } = content.content;
        const video = new MsgVideoContent();
        video.url = url; // 自己上传
        video.file = {
          path: url,
          name: "video",
        }; // SDK上传
        console.log("voice", { video, content });
        WKSDK.shared().chatManager.send(video, KOCSIM.inst().currentChannel);
        break;
      }
      case 101: {
        const wecatInfo = new WechatInfoContent();
        wecatInfo.url = content.content;
        wecatInfo.name = content.name;
        wecatInfo.desc = content.desc;
        WKSDK.shared().chatManager.send(wecatInfo, KOCSIM.inst().currentChannel);
        break;
      }
    }
  }

  // 设置 当前通道
  setCurrentChannel(channel: InitChannelData) {
    KOCSIM.inst().currentChannel = new Channel(channel.channelId, /* ChannelTypePerson */ ChannelTypeGroup);
    // 设置通道信息
    KOCSIM.inst().channelInfo = channel;
    // 保存到本地
    store.addServiceChannel({
      ...channel,
      // 额外存储 ws 和 uid , 复用通道前需要判断
      belongAddr: WKSDK.shared().config.addr,
      belongUid: WKSDK.shared().config.uid,
    });
  }

  // 获取频道消息
  async getChannelMessages(opts: SyncOptions) {
    const channel = new Channel(KOCSIM.inst().currentChannel.channelID, ChannelTypeGroup);
    const msgs = await WKSDK.shared().chatManager.syncMessages(channel, opts);
    msgs.forEach((msg: Message) => {
      KOCSIM.inst().onMessageAsync(msg);
    });
    return msgs;
  }

  // 获取配置
  getConfig() {
    return WKSDK.shared().config;
  }

  // 结束会话
  endChannel() {
    // 清除状态等
    KOCSIM.inst().currentChannel = new Channel("0", ChannelTypeGroup);
    KOCSIM.inst().channelInfo = {};
  }

  // 设置消息同步完成事件
  setOnMessageAsync(callback: OnMessageAsyncCallback) {
    KOCSIM.inst().onMessageAsync = callback;
  }
}
